package org.icop.virtdoc;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.icop.utils.AnnotationHandler;
import org.jbpt.graph.abs.IEdge;
import org.jbpt.graph.abs.IGraph;
import org.jbpt.hypergraph.abs.IVertex;

public class StandardVirtualDoc<G extends IGraph<E,V>, E extends IEdge<V>, V extends IVertex> implements VirtualDoc {

	protected List<String> terms;
	
	protected List<Integer> termCounts;
	
	protected List<Float> termWeights;
	
	/*
	 * Caching variables.
	 */
	int maxTermOccurrence = -1;

	protected StandardVirtualDoc() {
		this.terms = new ArrayList<>();
		this.termCounts = new ArrayList<>();
		this.termWeights = new ArrayList<>();
	}

	public StandardVirtualDoc(G graph, Collection<V> vertices) {
		this();
		Map<V, Map<String, String>> attributes = AnnotationHandler.getAnnotationsForGraph(graph);
		initDocForAllVertices(graph, vertices, attributes);
	}

	public StandardVirtualDoc(G graph, Collection<V> vertices, Map<V, Map<String, String>> attributes) {
		this();
		initDocForAllVertices(graph, vertices, attributes);
	}
	
	protected void initDocForSingleVertex(G g, V v, Map<String, String> attributesOfV) {
		
		if (attributesOfV == null)
			return;
		for (String att : attributesOfV.keySet()) {
			if (VirtualDocParams.shouldIgnoreAttribute(att))
				continue;
			String attString = attributesOfV.get(att);
			for (String term : VirtualDocParser.getInstance().parseDocEntry(attString)) {
				if (!this.terms.contains(term)) {
					this.terms.add(term);
					this.termCounts.add(1);
					this.termWeights.add(0f);
					increaseTermWeight(this.terms.size() - 1, att);					
				}
				else {
					int i = this.terms.indexOf(term);
					this.termCounts.set(i, this.termCounts.get(i) + 1);
					increaseTermWeight(i,att);
				}
			}
		}
	}
	
	protected void increaseTermWeight(int index, String attribute) {
			this.termWeights.set(index, this.termWeights.get(index) + VirtualDocParams.getAttributeWeight(attribute));
	}
	
	protected void initDocForAllVertices(G g, Collection<V> vertices, Map<V, Map<String, String>> attributes) {
		for (V v : vertices) {
			initDocForSingleVertex(g, v, attributes.get(v));
		}
	}
	
	public Collection<String> getAllTerms() {
		return terms;
	}
	
	@Override
	public String toString(){
		return this.terms.toString() + " " + this.termCounts.toString();
	}

	public float getTermWeightInDoc(String term) {
		if (!this.terms.contains(term))
			return 0;
		
		return this.termWeights.get(this.terms.indexOf(term));
	}
	
	public int getCountOfTerm(String term) {
		if (!this.terms.contains(term))
			return 0;
		
		return this.termCounts.get(this.terms.indexOf(term));
	}

	public int getMaxTermOccurrence() {
		if (!(maxTermOccurrence == -1))
			return maxTermOccurrence;
		
		maxTermOccurrence = 0;
		
		for (Integer c : this.termCounts) {
			maxTermOccurrence = Math.max(maxTermOccurrence, c);
		}
		return maxTermOccurrence;
	}
}
